package com.ywicc.commlibs.socket;

import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * author : zhouxuan77
 * e-mail : zhouxuan77@163.com
 * time   : 2022/03/17
 * desc   :
 * version: 1.0
 */
public class ClientManger {

    private final static int SERVER_INTERVAL_DATA_TIME = 2;

    private Socket socket;
    private boolean isStrict;
    private final SocketUtils socketUtils;
    public ExecutorService cachedThreadPool;
    public ScheduledThreadPoolExecutor scheduledThreadPool;
    private String strIP;
    private int port;
    private byte[] sendData;
    private RunnableScheduledFuture<?> runnableReceiveData;

    public ClientManger() {
        socketUtils = new SocketUtils();

        cachedThreadPool = Executors.newCachedThreadPool();
        scheduledThreadPool = new ScheduledThreadPoolExecutor(5);
    }

    public void initSocket(String strIP, int port) {
        this.strIP = strIP;
        this.port = port;

        cachedThreadPool.execute(initSocketRunnable);
    }

    public void stopSocket() {
        scheduledThreadPool.shutdown();
        cachedThreadPool.shutdown();

        if (socket != null) {
            try {
                socket.shutdownOutput();
                socket.shutdownInput();

                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendData(byte[] data) {
        this.sendData = data;

        cachedThreadPool.execute(sendDataRunnable);
    }

    public void receiveData() {
        cachedThreadPool.execute(receiveDataRunnable);
    }

    public void startLongReceiveData() {
        runnableReceiveData = (RunnableScheduledFuture<?>) scheduledThreadPool.scheduleAtFixedRate(receiveDataRunnable, 0, SERVER_INTERVAL_DATA_TIME, TimeUnit.SECONDS);
    }

    public void stopLongReceiveData() {
        scheduledThreadPool.remove(runnableReceiveData);
    }

    public void setStrictModule(int module) {
        isStrict = module == SocketUtils.SERVER_RECEIVE_STRICT;
    }

    ClientMangerImpl clientMangerImpl;

    public interface ClientMangerImpl {
        void callBackClientReceiveData(byte[] data);
    }

    public void setClientMangerImpl(ClientMangerImpl clientMangerImpl) {
        this.clientMangerImpl = clientMangerImpl;
    }

    Runnable initSocketRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                socket = new Socket(strIP, port);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    };

    Runnable sendDataRunnable = new Runnable() {
        @Override
        public void run() {
            socketUtils.sendData(socket, sendData, isStrict);
        }
    };

    Runnable receiveDataRunnable = new Runnable() {
        @Override
        public void run() {
            byte[] data = socketUtils.receiveData(socket, isStrict);

            if (data != null && clientMangerImpl != null) {
                clientMangerImpl.callBackClientReceiveData(data);
            }
        }
    };
}
